/*
 * Class
 * MainFrame
 */
package pl.abstractvoid.gui;

import java.awt.Cursor;
import static java.awt.Frame.MAXIMIZED_BOTH;
import java.awt.Insets;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.Introspector;
import java.io.File;
import java.io.FileInputStream;
import javax.swing.filechooser.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import pl.abstractvoid.datamodel.parameters.ParameterSet;
import pl.abstractvoid.datamodel.parameters.exceptions.NoSuchParameterException;
import pl.abstractvoid.distributions.AbstractDistribution;
import pl.abstractvoid.distributions.DistributionFactory;
import pl.abstractvoid.distributions.PlotType;
import pl.abstractvoid.distributions.exceptions.ParameterValidationFailException;
import pl.abstractvoid.gui.configuration.ChooseRDialog;
import pl.abstractvoid.gui.configuration.DefaultLanguageJDialog;
import pl.abstractvoid.languages.LanguageProvider;
import pl.abstractvoid.settings.SettingsProvider;
import pl.abstractvoid.rconnector.RInterpreter;
import rcaller.exception.ParseException;

/**
 * The main guide window
 * <p>
 * Consists of four areas: -DataInputPanel: Here is when all the input date for
 * the distribution is visible in form of nested TabbedPanes -DataOutputPanel:
 * All the output data is visible here -RConsolePanel: input and output
 * JTextFields that allow bidirectional communication with instance of R
 * -DistributionHelpDocumentPanel: here a help document for each distribution
 * can be displayed All the distributions are stored in HashMap<String,
 * AbstractDistribution>, where the key value is the distributionName+number,
 * which is reflected in concatenation of DistributionTab+InstanceTab in Data
 * input Panel. This setup allows for fast and easy binding of all component
 * with currently selected input tab.
 *
 * @author Wojciech Szałapski
 * @author Ivo Zieliński
 */
public class MainFrame extends javax.swing.JFrame {

    /**
     * Component observing current distribution.
     */
    private final ArrayList<DistributionStateObserver> stateObservers = new ArrayList();
    /**
     * The map of all distributions.
     */
    private HashMap<String, AbstractDistribution> distributions = new HashMap();
    /**
     * Currently active distribution.
     */
    private AbstractDistribution currentDistribution;
    /**
     * Pane with input parameters.
     */
    private DataInputPanel dataInputPanel;
    /**
     * Pane with output parameters.
     */
    private DataOutputPanel dataOutputPanel;
    /**
     * Pane with R console.
     */
    private RConsolePanel rConsolePanel;
    /**
     * Pane with distribution's help document.
     */
    private DistributionHelpDocumentPanel distributionHelpDocumentPanel;
    /**
     * Name of currently displayed distribution
     */
    private String currentKey;
    public static long roundingMode = 8;
    
    /**
     * Creates new form MainFrame.
     * <p>
     * Creates all components and subscribes all the observers.
     */
    public ArrayList<PlotFrame> plotFrames;

    public MainFrame() {
        loadSettings();
        setTitle("JRDistribution 1.0");
        try {
            setIconImage(UtilsGUI.createImage("/JRIcon.png"));
        } catch (IOException ex) {
            Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
        plotFrames = new ArrayList<>();
        dataInputPanel = new DataInputPanel(this);
        dataOutputPanel = new DataOutputPanel(this);
        rConsolePanel = new RConsolePanel(this);
        distributionHelpDocumentPanel = new DistributionHelpDocumentPanel(this);
        stateObservers.add(rConsolePanel);
        stateObservers.add(dataInputPanel);
        stateObservers.add(dataOutputPanel);
        stateObservers.add(distributionHelpDocumentPanel);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                for (Map.Entry d : distributions.entrySet()) {
                    ((AbstractDistribution) (d.getValue())).cleanUp();
                }
            }
        });
        setVisible(false);
        initComponents();
        superPane.setDividerLocation(0.5);
        parameterPane.setDividerLocation(0.3);
        rPane.setDividerLocation(0.85);
        setUpToolBar();
        setExtendedState(MAXIMIZED_BOTH);
        setVisible(true);
    }

    /**
     * Responsible for loading settings from config file (default language and 
     * location of R executable).
     */
    private void loadSettings() {
        if (SettingsProvider.getInstance().getProperty("defaultLanguage") == null
                || !LanguageProvider.getInstance().isAvailableLanguage(SettingsProvider.getInstance().getProperty("defaultLanguage"))) {
            DefaultLanguageJDialog languageChooser = new DefaultLanguageJDialog(this, true);
            UtilsGUI.centerWindow(languageChooser);
            languageChooser.setVisible(true);
        }
        LanguageProvider.getInstance().setLanguage(SettingsProvider.getInstance().getProperty("defaultLanguage"));
        if (SettingsProvider.getInstance().getProperty("RExecutableFile") == null
                || !(new File(SettingsProvider.getInstance().getProperty("RExecutableFile")).isFile())) {
            ChooseRDialog RChooser = new ChooseRDialog(this, true);
            UtilsGUI.centerWindow(RChooser);
            RChooser.setVisible(true);
            if (SettingsProvider.getInstance().getProperty("RExecutableFile") == null) {
                JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("errorMessage"), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
                System.exit(0);
            }
            if (!(new File(SettingsProvider.getInstance().getProperty("RExecutableFile")).isFile())) {
                JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("RExecutableDoesNotExist"), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
                System.exit(0);
            }
        }
    }

    /**
     * Used by child components to determine which distribution data should be 
     * displayed.
     * @return 
     */
    public AbstractDistribution getCurrentDistribution() {
        return currentDistribution;
    }

    /**
     * Creates new distribution.
     * <p>
     * New distribution is added to the HashMap, with a key which is
     * distribution name + (highest number of distribution instance tab +1). All
     * the observing components are notified about the creation of new
     * component.
     *
     * @param distributionClass class of the distribution which is created
     */
    public void createNewDistribution(Class<? extends AbstractDistribution> distributionClass) {
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        AbstractDistribution distribution = DistributionFactory.getDistribution(distributionClass);
        currentDistribution = distribution;
        dataInputPanel.newDistributionNotify();
        currentKey = dataInputPanel.getCurrentTabName();
        distributions.put(currentKey, distribution);
        dataOutputPanel.newDistributionNotify();
        rConsolePanel.newDistributionNotify();
        distributionHelpDocumentPanel.newDistributionNotify();
        System.out.println(LanguageProvider.getInstance().getString("rPromptConsoleReady"));
        setCursor(Cursor.getDefaultCursor());
    }

    /**
     * Called by DataInputPanel to signify change of selected tab.
     * <p>
     * Changes the current distribution and notifies all the observing
     * components about the tab change.
     *
     * @param tabName The name of the tab which was selected.
     */
    public void informAboutTabChange(String tabName) {
        if (!distributions.isEmpty()) {
            currentDistribution = distributions.get(tabName);
            currentKey = tabName;
            for (DistributionStateObserver obs : stateObservers) {
                obs.distributionChangedNotify();
            }
        }
    }

    /**
     * Called by RConsolePanel to signify execution of code.
     */
    public void notifyCodeExecuted() {
        executeCodeActionPerformed();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        superPane = new javax.swing.JSplitPane();
        rPane = new javax.swing.JSplitPane();
        newInstanceButton = new javax.swing.JButton();
        parameterPane = new javax.swing.JSplitPane();
        optionsToolbar = new javax.swing.JToolBar();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        superPane.setDividerSize(3);
        superPane.setResizeWeight(0.5);

        rPane.setDividerSize(3);
        rPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        rPane.setResizeWeight(0.5);

        newInstanceButton.setText("newInstance");
        newInstanceButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newInstanceButtonActionPerformed(evt);
            }
        });
        rPane.setTopComponent(newInstanceButton);

        superPane.setRightComponent(rPane);
        rPane.setLeftComponent(rConsolePanel);
        rPane.setRightComponent(dataOutputPanel);

        parameterPane.setDividerSize(3);
        parameterPane.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        parameterPane.setResizeWeight(0.8);
        superPane.setLeftComponent(parameterPane);
        parameterPane.setLeftComponent(dataInputPanel);
        parameterPane.setRightComponent(distributionHelpDocumentPanel);

        getContentPane().add(superPane, java.awt.BorderLayout.CENTER);

        optionsToolbar.setBackground(new java.awt.Color(255, 255, 255));
        optionsToolbar.setBorderPainted(false);
        getContentPane().add(optionsToolbar, java.awt.BorderLayout.PAGE_START);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    /**
     * Creates new instance of currently selected distribution class.
     * @param evt 
     */
    private void newInstanceButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newInstanceButtonActionPerformed
        if (currentDistribution == null) {
            JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("noDistributionLoaded"), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
        } else {
            createNewDistribution(currentDistribution.getClass());
        }
    }//GEN-LAST:event_newInstanceButtonActionPerformed

    /**
     * Shows plots generated by in a PlotFrame class.
     */
    private void showGeneratedPlots() {
        currentDistribution.getrState().runCustomCode("", RInterpreter.plotRList);
        String[] plotPaths = currentDistribution.getrState().getPlotsPaths();
        int plotNumber = 1;
        ArrayList<ImageIcon> plots = new ArrayList<>();
        for (String path : plotPaths) {
            ImageIcon plotImage = new ImageIcon(path.replaceAll("\\\\\\\\", "/"));
            plots.add(plotImage);
            ++plotNumber;
        }
        if (plots.size() > 0) {
            PlotFrame plotFrame = new PlotFrame(plots, "plots", this);
            UtilsGUI.centerWindow(plotFrame);
            plotFrame.setVisible(true);
            plotFrames.add(plotFrame);
        }
    }

    /**
     * Executes the commands/script entered in the RConsole pannel, and calls
     * the RCaller associated with the current distribution to execute it.
     * If new data is generated, all the components are prompted to display it.
     */
    private void executeCodeActionPerformed() {
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        if (currentDistribution == null) {
            setCursor(Cursor.getDefaultCursor());
            return;
        }
        currentDistribution.getrState().loadParameters(currentDistribution.getParameters());
        String inputCode = rConsolePanel.getInputCode();
        System.out.println("$ " + inputCode);
        currentDistribution.getrState().runCustomCode(inputCode);
        try {
            currentDistribution.updateInput(currentDistribution.loadParameters());
        } catch (ParseException pex) {
            System.out.println(LanguageProvider.getInstance().getString("incorrectParameters"));
        } catch (NoSuchParameterException ex) {
            JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("errorMessage"), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
        }
        ((TablePanel) ((JTabbedPane) (((JTabbedPane) (dataInputPanel.getComponent(0))).getSelectedComponent())).getSelectedComponent()).updateParameters(currentDistribution.getParameters());
        showGeneratedPlots();
        setCursor(Cursor.getDefaultCursor());
    }

    /**
     * Calls for execution of RScript responsible for generating the distribution
     * output associated with the current distribution.
     */
    private void computeOutputAction() {
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        if (currentDistribution != null) {
            currentDistribution.getrState().loadParameters(currentDistribution.getParameters());
            try {
                currentDistribution.updateOutput();
            } catch (NoSuchParameterException | IOException ex) {
                JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("errorMessage"), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
            } catch (ParameterValidationFailException ex) {
                if (ex.getMessage() == null) {
                    JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("errorMessage"), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
                } else {
                    JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getDistributionString(ex.getMessage()), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
                }
            }
            dataOutputPanel.updateUI();
        } else {
            JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("noDistributionLoaded"), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
        }
        setCursor(Cursor.getDefaultCursor());
    }

    /**
     * Displays the selected plot of the current distribution in a PlotFrame window.
     * @param plotType 
     */
    private void showPlotAction(PlotType plotType) {
        computeOutputAction();
        if (currentDistribution != null) {
            ImageIcon plotImage;
            String plotTitle;
            switch (plotType) {
                case PROBABILITY_PLOT:
                    plotImage = currentDistribution.getProbabilityPlotImage();
                    plotTitle = "probabilityPlot";
                    break;
                case CUMULATIVE_DISTRIBUTION_PLOT:
                    plotImage = currentDistribution.getCumulativeDistributionPlotImage();
                    plotTitle = "cumulativeDistributionPlot";
                    break;
                default:
                    JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("errorMessage"), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
                    return;
            }
            if (plotImage != null) {
                PlotFrame plotFrame = new PlotFrame(plotImage, plotTitle, this);
                UtilsGUI.centerWindow(plotFrame);
                plotFrame.setVisible(true);
                plotFrames.add(plotFrame);
            } else {
                JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("noPlotFound"), LanguageProvider.getInstance().getString("error"), JOptionPane.INFORMATION_MESSAGE);
            }
        } else {
            JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("noDistributionLoaded"), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * Adjusts the rounding mode. Rounding mode is used by the JTable components,
     * namely the TableModels, to display values in a desired decimal form.
     */
    private void addDecimalActionPerformed() {
        if (roundingMode < 15) {
            roundingMode++;
        }
        dataInputPanel.updateUI();
        dataOutputPanel.updateUI();
    }

    /**
     * Adjusts the rounding mode.
     */
    private void removeDecimalActionPerformed() {
        if (roundingMode > 1) {
            roundingMode--;
        }
        dataInputPanel.updateUI();
        dataOutputPanel.updateUI();
    }

    /**
     * Deletes the current distributions and notifies all the child components.
     */
    private void deleteInstanceActionPerformed() {
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        String oldKey = dataInputPanel.getCurrentTabName();
        if (oldKey != null) {
            for (DistributionStateObserver obs : stateObservers) {
                obs.distributionDeletedNotify(distributions.size() == 1);
            }
            distributions.get(oldKey).cleanUp();
            distributions.remove(oldKey);

            currentKey = dataInputPanel.getCurrentTabName();
            currentDistribution = distributions.get(currentKey);
            if (!distributions.isEmpty()) {
                for (DistributionStateObserver obs : stateObservers) {
                    obs.distributionChangedNotify();
                }
            }
        }
        setCursor(Cursor.getDefaultCursor());
    }

    /**
     * Displays the SettingsJFrame window and applies the selected settings if 
     * they were altered.
     */
    private void settingsMenuOpenedActionPerformed() {
        String oldLanguage = LanguageProvider.getInstance().getCurrentLanguageCode();
        SettingsJFrame settingsFrame = new SettingsJFrame(this, true);
        if (!LanguageProvider.getInstance().getCurrentLanguageCode().equals(oldLanguage)) {
            dataInputPanel.reloadParameters();
            dataOutputPanel.reloadParameters();
            if (currentDistribution != null) {
                distributionHelpDocumentPanel.newDistributionNotify();
            } else {
                distributionHelpDocumentPanel.distributionChangedNotify();
                rConsolePanel.loadInitialState();
            }
            for (Map.Entry mapEntry : distributions.entrySet()) {
                ((AbstractDistribution) mapEntry.getValue()).reloadLanguage();
            }
            rConsolePanel.reloadInitialMessage();
        }
    }

    /**
     * Serializes all distributions in a file.
     */
    private void saveSession() {
        if (distributions.isEmpty()) {
            return;
        }
        File file = null;
        final JFileChooser fileChooser = new JFileChooser();
        if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
            file = fileChooser.getSelectedFile();
        }
        if (file != null) {
            file = new File(file.getAbsolutePath() + ".jrd");
            try {
                try (FileOutputStream fileOut = new FileOutputStream(file); ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
                    out.writeObject(distributions);
                }
            } catch (IOException i) {
                JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("fileSaveError"), LanguageProvider.getInstance().getString("error"), JOptionPane.INFORMATION_MESSAGE);
            }
        }
    }

    /**
     * Deserializes distributions from a file.
     */
    private void loadSession() {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setAcceptAllFileFilterUsed(false);
        fileChooser.addChoosableFileFilter(new FileFilter() {
            @Override
            public boolean accept(File f) {
                if (f.isDirectory()) {
                    return true;
                }
                return f.getName().endsWith(".jrd");
            }

            @Override
            public String getDescription() {
                return LanguageProvider.getInstance().getString("jrdFileType");
            }
        });
        File file;
        HashMap<String, AbstractDistribution> newDistributions = null;
        if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
            file = fileChooser.getSelectedFile();
            try {
                this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                try (FileInputStream fileIn = new FileInputStream(file); ObjectInputStream in = new ObjectInputStream(fileIn)) {
                    newDistributions = (HashMap<String, AbstractDistribution>) in.readObject();
                }
            } catch (IOException | ClassNotFoundException ex) {
                JOptionPane.showMessageDialog(this, ex.getMessage(), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
                return;
            }
            if (newDistributions == null) {
                JOptionPane.showMessageDialog(this, "new distro==null!", LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
                return;
            }
            for (Map.Entry pair : distributions.entrySet()) {
                AbstractDistribution dist = (AbstractDistribution) pair.getValue();
                dist.cleanUp();
            }
            distributions = new HashMap<>();
            for (DistributionStateObserver obs : stateObservers) {
                obs.distributionsLoadedNotify();
            }
            for (Map.Entry pairs : newDistributions.entrySet()) {
                currentDistribution = (AbstractDistribution) pairs.getValue();
                ParameterSet ps = currentDistribution.getParameters();
                for (DistributionStateObserver obs : stateObservers) {
                    obs.newDistributionNotify();
                }
                currentKey = dataInputPanel.getCurrentTabName();
                distributions.put(currentKey, currentDistribution);
                System.out.println(LanguageProvider.getInstance().getString("rPromptConsoleReady"));
            }
            this.setCursor(Cursor.getDefaultCursor());
        }
    }

    private void displayHelpDocumentActionPerformed() {
        new HelpJFrame().setVisible(true);
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;

                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class
                    .getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new MainFrame().setVisible(true);
            }
        });
    }

    /**
     * Creates the toolbar.
     */
    public final void setUpToolBar() {
        optionsToolbar.removeAll();
        optionsToolbar.setMargin(new Insets(0, 0, 0, 0));
        optionsToolbar.setFloatable(false);
        dataInputPanel.updateTabNames();
        for (PlotFrame plotFrame : plotFrames) {
            plotFrame.reloadTitle();
        }
        JButton button;
        try {
            button = UtilsGUI.createButton("/copyDistribution", LanguageProvider.getInstance().getString("newCurrentDistributionTooltip"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    newInstanceButtonActionPerformed(evt);
                }
            });
            optionsToolbar.add(button);
            button = UtilsGUI.createButton("/deleteDistribution", LanguageProvider.getInstance().getString("deleteCurrentDistributionTooltip"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    deleteInstanceActionPerformed();
                }
            });
            optionsToolbar.add(button);
            button = UtilsGUI.createButton("/saveState", LanguageProvider.getInstance().getString("saveDistributionTooltip"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    saveSession();
                }
            });
            optionsToolbar.add(button);
            button = UtilsGUI.createButton("/loadState", LanguageProvider.getInstance().getString("loadDistributionTooltip"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    loadSession();
                }
            });
            optionsToolbar.add(button);
            button = UtilsGUI.createButton("/settings", LanguageProvider.getInstance().getString("settings"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    settingsMenuOpenedActionPerformed();
                }
            });
            optionsToolbar.add(button);
            button = UtilsGUI.createButton("/addDecimal", LanguageProvider.getInstance().getString("increasePrecision"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    addDecimalActionPerformed();
                }
            });
            optionsToolbar.add(button);
            button = UtilsGUI.createButton("/removeDecimal", LanguageProvider.getInstance().getString("decreasePrecision"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    removeDecimalActionPerformed();
                }
            });
            optionsToolbar.add(button);
            button = UtilsGUI.createButton("/helpButton", LanguageProvider.getInstance().getString("decreasePrecision"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    displayHelpDocumentActionPerformed();
                }
            });
            optionsToolbar.add(button);

            optionsToolbar.addSeparator();

            button = UtilsGUI.createButton("/executeCommand", LanguageProvider.getInstance().getString("runRScriptTooltip"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    executeCodeActionPerformed();
                }
            });
            optionsToolbar.add(button);
            button = UtilsGUI.createButton("/computeOutput", LanguageProvider.getInstance().getString("computeOutputTooltip"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    computeOutputAction();
                }
            });
            optionsToolbar.add(button);
            button = UtilsGUI.createButton("/showProbabilityPlot", LanguageProvider.getInstance().getString("displayProbabilityGraphTooltip"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    showPlotAction(PlotType.PROBABILITY_PLOT);
                }
            });
            optionsToolbar.add(button);
            button = UtilsGUI.createButton("/showCumulativeDistributionPlot", LanguageProvider.getInstance().getString("displayCumulativeDistributionGraphTooltip"), "png");
            optionsToolbar.add(button);
            button.addActionListener(new java.awt.event.ActionListener() {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    showPlotAction(PlotType.CUMULATIVE_DISTRIBUTION_PLOT);
                }
            });
            optionsToolbar.add(button);
            optionsToolbar.addSeparator();

            ArrayList<Class<? extends AbstractDistribution>> distributionsList = DistributionFactory.getDistributionsList();
            for (Class<? extends AbstractDistribution> distributionType : distributionsList) {
                final String distributionName = distributionType.getSimpleName();
                final Class<? extends AbstractDistribution> distributionClass = distributionType;
                button = UtilsGUI.createButton("/new" + distributionName, LanguageProvider.getInstance().getString(Introspector.decapitalize(distributionName) + "Tooltip"), "png");
                optionsToolbar.add(button);
                button.addActionListener(new java.awt.event.ActionListener() {
                    @Override
                    public void actionPerformed(java.awt.event.ActionEvent evt) {
                        createNewDistribution(distributionClass);
                    }
                });
            }
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(this, LanguageProvider.getInstance().getString("errorMessage"), LanguageProvider.getInstance().getString("error"), JOptionPane.ERROR_MESSAGE);
            dispose();
        }
    }

    public String getCurrentKey() {
        return currentKey;
    }

    public HashMap<String, AbstractDistribution> getDistributions() {
        return distributions;
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton newInstanceButton;
    private javax.swing.JToolBar optionsToolbar;
    private javax.swing.JSplitPane parameterPane;
    private javax.swing.JSplitPane rPane;
    private javax.swing.JSplitPane superPane;
    // End of variables declaration//GEN-END:variables
}
